package service

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"math"
	"tinyrdm/server/db"
	"tinyrdm/server/models"
	"tinyrdm/server/utils"
)

var storage = db.NewLocalStore("users.yaml")

type UserService struct {
}

type UserDB struct {
	Users []models.User `yaml:"users"`
}

func loadUsers() (*UserDB, error) {
	var userDB *UserDB
	err := storage.Load(&userDB)
	if err != nil {
		return nil, err
	}
	if userDB == nil {
		userDB = &UserDB{
			Users: make([]models.User, 0),
		}
	}
	if userDB.Users == nil {
		userDB.Users = make([]models.User, 0)
	}
	return userDB, nil
}

func NewUserService() *UserService {
	return &UserService{}
}

func getUser(account string) (*models.User, error) {
	var userDB, err = loadUsers()
	if err != nil {
		return nil, err
	}
	for _, user := range userDB.Users {
		if user.Account == account {
			return &user, nil
		}
	}
	return nil, errors.New("用户不存在！")
}

func addUser(newUser models.User) error {
	var userDB, err = loadUsers()
	if err != nil {
		return err
	}
	var isNew = true
	var maxId = 1
	for _, user := range userDB.Users {
		if user.Account == newUser.Account {
			isNew = false
			user.Nickname = newUser.Nickname
			user.Password = newUser.Password
			user.Roles = newUser.Roles
			user.Remark = newUser.Remark
			newUser.Id = user.Id
		}
		maxId = int(math.Max(float64(maxId), float64(user.Id)))
	}
	if isNew {
		newUser.Id = maxId + 1
		userDB.Users = append(userDB.Users, newUser)
	}
	err = storage.Store(userDB)
	return err
}

func (u *UserService) Login(loginData *models.User) (*models.RespData, *models.User) {
	cipherPassword := loginData.Password

	user, err := getUser(loginData.Account)

	if err != nil {
		return models.NewErrorResp(err), nil
	}
	encryptPassword := utils.GetSHA256HashCode(cipherPassword)
	if encryptPassword != user.Password {
		return models.ErrorResp("用户名或者密码不正确！"), nil
	}
	user.Password = ""
	return models.SuccessResp(user), user
}

func (u *UserService) SignUp(req []byte) *models.RespData {

	var user models.User
	err := json.Unmarshal(req, &user)
	if err != nil {
		logs.Error(err, req)
		return models.NewErrorResp(err)
	}

	if len(user.Account) == 0 || len(user.Password) == 0 {
		return models.ErrorResp("账号或者密码不能为空！")
	}
	if len(user.Nickname) == 0 {
		user.Nickname = user.Account
	}
	user.Password = utils.GetSHA256HashCode(user.Password)
	err = addUser(user)
	if err != nil {
		return models.NewErrorResp(err)
	}

	return models.SuccessResp(user).SetMsg("注册成功！")
}

func InitAdmin() {
	reset := beego.AppConfig.DefaultBool("reset_admin_password", false)
	logs.Info("InitAdmin", reset)

	admin, err := getUser("admin")
	if err != nil {
		logs.Warn("getUser error", err)
		admin = &models.User{
			Id:       0,
			Account:  "admin",
			Nickname: "admin",
			Roles:    "ADMIN",
			Password: "",
			Remark:   "",
		}
	}
	if admin.Id > 0 && !reset {
		logs.Info("admin has exist and reset is false, skip")
		return
	}
	password := beego.AppConfig.DefaultString("admin_password", randPassword(10))
	admin.Password = utils.GetSHA256HashCode(password)
	admin.Remark = "admin"
	admin.Roles = "ADMIN"
	err = addUser(*admin)
	if err != nil {
		logs.Warn("insert or update admin fail", err)
	} else {
		logs.Warn(fmt.Sprintf("admin password is:  %s", password))
	}

}

func randPassword(n int) string {
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		return "123456"
	}
	return base64.StdEncoding.EncodeToString(b)
}
